package com.timmy.google_play.base;

import android.support.annotation.NonNull;

import com.google.gson.Gson;
import com.timmy.google_play.conf.Constants;
import com.timmy.google_play.utils.FileUtils;
import com.timmy.google_play.utils.HttpUtils;
import com.timmy.google_play.utils.IOUtils;
import com.timmy.google_play.utils.LogInterceptor;
import com.timmy.google_play.utils.LogUtils;
import com.timmy.google_play.utils.UIUtils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * Created by Timmy on 2016/12/10.
 * 网络请求封装的基类
 */

public abstract class BaseProtocol<T> {

    private int mIndex;

    public T loadData(int index) throws Exception {

        T result = null;

        //从内存返回
        result = loadDataFromMem(index);

        if (result != null) {
            LogUtils.s("从内存加载数据-->" + generateCachekey(index));
            return result;
        }

        //优先从本地加载网络数据
        result = loadDataFromLocal(index);


        if (result != null) {
            //本地存有有效的缓存
            LogUtils.sf("从本地加载数据成功-->" + getCacheFile(index).getAbsolutePath());
            return result;
        }

        //网络加载数据,存入本地,返回状态
        result = loadDataFromNet(index);
        return result;

    }

    /**
     * 从内存加载数据
     */
    private T loadDataFromMem(int index) {

        //找到存储结构
        MyApplication myApp = (MyApplication) UIUtils.getContext();

        Map<String, String> cacheMap = myApp.getCacheMap();

        //生成缓存的key
        String key = generateCachekey(index);


        if (cacheMap.containsKey(key)) {
            //有
            String memData = cacheMap.get(key);

            //解析
            return parseData(memData, new Gson());
        }

        return null;
    }

    //从本地缓存加载网络数据
    private T loadDataFromLocal(int index) {

        BufferedReader reader = null;

        try {
            File cacheFile = getCacheFile(index);

            //判断是否存在
            if (cacheFile.exists()) {
                //存在,读取缓存生成时间 ---> 缓存文件的第一行
                reader = new BufferedReader(new FileReader(cacheFile));

                // 缓存文件的第一行
                String firstLine = reader.readLine();

                long cacheInserTime = Long.parseLong(firstLine);

                if (System.currentTimeMillis() - cacheInserTime < Constants.protocol_timeout) {
                    //有效缓存
                    String cacheData = reader.readLine();

                    //保存数据到内存当中
                    saveData2Mem(index,cacheData);


                    //解析
                    return parseData(cacheData, new Gson());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关流
            IOUtils.close(reader);
        }

        return null;
    }

    /**
     * 保存数据到内存当中
     */
    private void saveData2Mem(int index, String cacheData) {

        //缓存的key
        String key = generateCachekey(index);

        //得到存储结构
        MyApplication myApp = (MyApplication) UIUtils.getContext();

        Map<String, String> cacheMap = myApp.getCacheMap();

        //存储
        cacheMap.put(key,cacheData);

        LogUtils.s("保存数据到内存当中--->" + key);

    }


    /**
     * 得到缓存文件
     */
    private File getCacheFile(int index) {
        String dir       = FileUtils.getDir("json");
        String fileName  = generateCachekey(index); // 唯一
        File   cacheFile = new File(dir, fileName);

        return cacheFile;
    }

    /**
     * 本地生成缓存的key
     */
    @NonNull
    protected String generateCachekey(int index) {
        return getInterfaceKey() + "." + index;
    }

    private T loadDataFromNet(int index) throws IOException {

        mIndex = index;

        //1.创建自定义的日志拦截器
        LogInterceptor logInterceptor = new LogInterceptor();

        //2.创建okHttpClient对象--- 执行请求
        OkHttpClient httpClient = new OkHttpClient
                .Builder()
                .addInterceptor(logInterceptor)
                .build();

        //3.创建请求对象
        String url = Constants.URLS.BASEURL + getInterfaceKey();

        Map<String, Object> map = new HashMap<>();
        initParamsMapData(map);


        //参数拼接
        String urlParamsByMap = HttpUtils.getUrlParamsByMap(map);

        url = url + "?" + urlParamsByMap;

        Request request = new Request.Builder().get().url(url).build();

        //4.执行   同步执行
        Response response = httpClient.newCall(request).execute();

        if (response.isSuccessful()) {      //200

            //请求成功,解析数据
            String body = response.body().string();

            //保存数据到本地
            savaData2Local(body, index);

            //保存数据到内存当中
            saveData2Mem(index,body);

            Gson gson = new Gson();

            return parseData(body, gson);
        }

        return null;
    }

    protected void initParamsMapData(Map<String, Object> map) {
        map.put("index", mIndex);
    }

    /**
     * 保存数据到本地
     *
     * @param body  保存的数据
     * @param index
     */
    private void savaData2Local(String body, int index) {

        BufferedWriter writer = null;

        try {
            File cacheFile = getCacheFile(index);

            writer = new BufferedWriter(new FileWriter(cacheFile));

            //=============================== 写 ======================

            //第一行,写入当前系统时间,缓存的生成时间
            writer.write(System.currentTimeMillis() + "");

            //第二行,写入json文件
            writer.newLine();       //换行
            writer.write(body);

            LogUtils.s("缓存数据到本地-->" + cacheFile.getAbsolutePath());

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtils.close(writer);
        }
    }


    /**
     * 得到协议的关键字
     */
    @NonNull
    protected abstract String getInterfaceKey();
    // return "home";

    /**
     * gson解析请求回回来的数据
     */
    protected T parseData(String body, Gson gson) {

        Type type = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];

        T t = gson.fromJson(body,type);

        return t;
    }

}
